perm filename HAL.CLN[HAL,HE] blob sn#149515 filedate 1975-03-04 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00025 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00007 00002	INTRODUCTION TO HAL: A SIMPLE TRANSLATION FROM WAVE.
 00008 00003	SYNTAX OF HAL
 00014 00004	MORE SYNTAX.  DECLARATIONS
 00016 00005	STILL MORE SYNTAX:  WORLDS, MACROS.
 00017 00006	SEMANTICS OF HAL.
 00027 00007		SIMPLE MOVES
 00043 00008	SOME SAMPLES OF HAL CODE, WHICH DEMONSTRATE THE SYNTAX
 00046 00009	COMPLEX MOVES.
 00055 00010	TYPES OF VARIABLES.
 00064 00011	ARITHMETIC.
 00075 00012	DEFERRED EVALUATION
 00079 00013	DATA STRUCTURES FOR REPRESENTATION OF OBJECTS.
 00081 00014	COMPILE TIME AND RUNTIME MODIFICATION OF VARIABLES
 00087 00015	CONTROL STRUCTURES.
 00091 00016	IDEAS WHICH MUST BE THOUGHT OUT.  THEIR TIME HAS ALMOST COME.
 00095 00017	THE FOLLOWING PAGES ARE FOR COMMENTS & COMPLAINTS BY POTENTIAL USERS.
 00096 00018		...	SAMPLE PROGRAM : SLIP_OVER  (OCT 10)
 00102 00019		...	SAMPLE PROGRAM : PUT_PISTON_IN_VISE   (OCT 12)
 00108 00020		...	A REWORK OF PUT_PISTON_IN_VISE (W/ SETS, RESTORES ...NOV 6)
 00118 00021		...	RANDOM COMMENTS
 00120 00022		...	SAMPLE PROGRAM : BOLT_ON_FROB   (OCT 22)
 00128 00023		...	MORE COMMENTS (WHILE I'M THINKING OF THEM)
 00129 00024		...
 00130 00025		...
 00131 ENDMK
⊗;
INTRODUCTION TO HAL: A SIMPLE TRANSLATION FROM WAVE.

SAMPLE OF WAVE:
VECT DF
0 0 -40
VECT MV
0 0 80
FORCE DF NIL
STOP NIL MV
FREE 1 Z
SCREW 60
MERGE
CHANGE NIL 0 NIL 0 30

EQUIVALENT HAL CODE:
MOVE YELLOW
	TO ⊗  COMMENT:  ⊗ means current location;
	ON TORQUE(ZVECT(YELLOW)) > 80 DO STOP  
	COMMENT: STOP CAUSES THE ARM TO STOP, THEREBY TERMINATING THE MOVE;
	USING TIME ≥ 30
	MAINTAINING FORCE(ZVECT(YELLOW)*-40), FREE(ZVECT(YELLOW))
	DURING SCREW(60);
		COMMENT:  COMMANDS OF SCREWING HAVE TIME LIMITS, WHICH
		IN THIS CASE IS SET BY THE COMPILER.
SYNTAX OF HAL

NOTE ON THE BNF: * IS KLEENE STAR, [] IS OPTIONAL, {} ARE BRACKETS.
THIS PAGE IS BEING UPDATED WHENEVER NEW IDEAS OCCUR.
LAST UPDATE:  5/01/74

<PROGRAM> ::= <STATEMENT>

<STATEMENT> ::= <BLOCK> | <ASSIGNMENT> | <COMMAND> | <LABEL>: <STATEMENT> |
	<STOP> | <DONE>| <DECLARATION>
	IF <BOOL EXPR> THEN <STATEMENT> ELSE <STATEMENT> |
	<FOR STATEMENT> | <ASSUME> | <CHECK> | <DYNAMIC ATTACHMENT STATEMENT> |
	<WHENEVER STATEMENT> | <SIMULTANEOUS BLOCK> | <WORLD MANIPULATION>

<BLOCK> ::= BEGIN [<STRING>] [<STATEMENT> { ; <STATEMENT>}*] END

<SIMULTANEOUS BLOCK> ::= 
	COBEGIN <STATEMENT> [; <STATEMENT>]* COEND

<COMMAND> ::= <SIMPLE MOVE> | <COMPLEX MOVE> | <CENTER> | <DRIVE>
	| <SEARCH> | <VISE COMMAND> | <FINGERS COMMAND>

<SIMPLE MOVE> ::=
	{MOVE | GO} <CONTROLLABLE FRAME>
	TO <FRAME EXPR> [THEN <STATEMENT>]
	[TRACING <PARAMETERIZED FRAME>]
	[MAINTAINING ORIENTATION]
	[FROM <FRAME EXPR>]
	[VIA <DECORATED FRAME LIST>]
	[USING <PERFORMANCE SPEC LIST>]
	[DURING <STATEMENT>]
	[ON <BOOL EXPR> DO <STATEMENT> [, <BOOL EXPR> DO <STATEMENT>]* ]
	[MEANWHILE <STATISTICS REQUEST LIST>]

<SIMULTANEOUS MOVE> ::=
	{MOVE | GO} <CONTROLLABLE FRAME PAIR>
	TO <FRAME PAIR EXPR> [THEN <STATEMENT>]
	[TRACING <PARAMETERIZED FRAME PAIR>]
	[MAINTAINING ORIENTATION]
	[FROM <FRAME PAIR EXPR>]
	[VIA <DECORATED FRAME LIST>]
	[USING <PERFORMANCE SPEC LIST>]
	[DURING <STATEMENT>]
	[ON <BOOL EXPR> DO <STATEMENT> [, <BOOL EXPR> DO <STATEMENT>]* ]
	[MEANWHILE <STATISTICS REQUEST LIST>]

<CONTROLLABLE FRAME> ::= <ARM> | <FRAME ATTACHED TO A CONTROLLABLE FRAME>

<CONTROLLABLE FRAME PAIR> ::=
	'{ <CONTROLLABLE FRAME> , <CONTROLLABLE FRAME> '}

<ARM> ::= {YELLOW | BLUE}

<DECORATED FRAME LIST> ::= <DECORATED FRAME> [, <DECORATED FRAME LIST>]
<DECORATED FRAME> ::= <FRAME EXPR> [:<DECOR>]* [THEN <STATEMENT>]
<DECOR> ::= VEL=<VECTOR EXPR> | DURATION {≥ | ≤} <ARITH EXPR> |
		| APPROACH = <VECT EXPR> | DEPARTURE = <VECTOR EXPR>

<PERFORMANCE SPEC LIST> ::= <PERF SPEC> [, <PERF SPEC LIST>]
<PERF SPEC> ::= DURATION {≥ | ≤} <ARITH EXPR> | FORCE = <VECT EXPR>
	| FREE = <VECT EXPR LIST> | DEPARTURE = <VECT EXPR>
	| APPROACH = <VECT EXPR> | MASS=<SCALAR>

<PARAMETERIZED FRAME> ::=
	{{LOC = <PARAMETERIZED VECTOR>, ORIENT = <PARAMETERIZED ORIENTATION>} |
	<PARAM FRAME EXPR> } FOR <PARAM> ← <SCALAR> BY <GRAIN> UNTIL <SCALAR>
	[WITHIN <TOLERANCE>]

<GRAIN> ::= <SCALAR>

<SEARCH> ::=
	SEARCH <CONTROLLABLE FRAME>
	{ACROSS <PLANE EXPR> | NORMAL_TO <VECTOR EXPR>}
	INCREMENT = <SCALAR EXPR>
	REPEATING <STATEMENT>
	[THEN <STATEMENT>]
	[FROM etc]
	[DURING etc]
	[ON etc]

<CENTER> ::=
	CENTER <ARM>
	{ACROSS <PLANE EXPR> | NORMAL_TO <VECTOR EXPR>}
	[DURING etc]
	[ON etc]

<DRIVE> ::=
	DRIVE <ARM> (<INTEGER EXPR>)
	TO <SCALAR EXPR>
	[TRACING <PARAMETERIZED SCALAR>]
	[DURING etc]
	[ON etc]
	[THEN etc]

<WHENEVER STATEMENT> ::= WHENEVER <BOOL EXPR> DO <STATEMENT>

<CONSTRAINT STATEMENT> ::=
	CONSTRAIN [<CONSTRAINT> ,]* <CONSTRAINT>

<CONSTRAINT> ::=
	{LIKE:   0 ≤ THETA < π ; OR 3*X < Y + Z}
	<LINEAR PARAMETER EXPR> (<|>|≤|≥|=) <SEXP>

<LINEAR PARAMETER EXPR> ::=
	<PARAMETER> | <SEXP> * PARAMETER | <LIN PAR EXP> + <LIN PAR EXP>

MORE SYNTAX.  DECLARATIONS

<DECLARATION> ::= 
	<TYPE> <IDENTIFIER LIST> |
	<TYPE> ARRAY <IDENTIFIER LIST> <BOUNDS LIST>

<TYPE> ::=
	SCALAR
	PARAMETER
	PLANE
	VECTOR
	FRAME
	TRANS
	ATOM
	PROPERTY
	STRING
	LABEL


<UNITS STATEMENT> ::= <UNITS OPTION LIST>
<UNITS OPTION> ::= CM | INCHES | JIFFIES | SECONDS | MILLISECONDS |
	KG | GM | LBS | OZ | RADIANS | DEGREES | BOLLES | EULER
	| TAYLOR | GEOMED

<PROCEDURE DECLARATION> ::=
	PROCEDURE <NAME> (<ARGUMENT LIST>);
	BEGIN
	ASSUME <ARG> AT <FRAME EXPR> [WITHIN <TOLERANCE>];
		one assumption is required for each frame in the arg list.
	<STATEMENT>
	END

<TOLERANCE> ::= <VECTOR>
STILL MORE SYNTAX:  WORLDS, MACROS.


<WORLD MANIPULATION> ::=
	SAVE WORLD <WORLD NAME> | RESTORE WORLD <WORLD NAME>

<ASSUMPTION> ::=  ASSUME <FRAME> AT <FRAME EXPR>

<CHECK> ::= CHECK <WORLD BOOLEAN>

<ATTACH STATEMENT> ::=
	ATTACH <FRAME> TO <FRAME>

<DETACH STATEMENT> ::=
	DETACH <FRAME>
SEMANTICS OF HAL.

	HAL  obeys traditional  ALGOL  block  structure.   There  are
variables  of several  types,   which must be  declared.   The entire
program is a  statement.   In order  to allow flexible  editing of  a
running program,   it is  a good idea  to name important  blocks with
strings,   as in SAIL.   Then it should be  possible to modify source
code when in the interactive mode of HAL.
    	The purpose of  blocks is to 1) separate  variables, allowing
for  reclamation of  storage, 2)  keeping  the scope  of simultaneity
under control  (as  it  is not  legal  to  leave a  block  until  all
processes in it have terminated).

	SIMPLE MOVES
	A move is simple if it involves only one arm.   There are two
varieties  of  move:  MOVE  and  GO.   The  former  causes  a  smooth
trajectory to be  compiled.   The latter lets  the servo  do all  the
calculation, and the arm will stop after each segment of the motion.
	Certain things must be  specified in any move.   First is the
arm which  must be moved.  This can  be specified directly (as YELLOW
or BLUE) or by specifying a frame  which is to be moved.  A FRAME  is
a location with  an orientation.  Wherever the hand  is constitutes a
frame.   YELLOW is a frame.  Certain objects will have frames on them
also. It is  possible to attach frames  to arms.   So if the hand  is
holding a frob,  it  is perfectly reasonable to request that the frob
be moved to a particular  location.  So if  FROB is a frame  attached
to BLUE, then both FROB and BLUE are <controllable frame>s.
	Next, the destination  must be specified.  This  is specified
as a frame, of  course.  MOVE BLUE TO F1 means that at the end of the
motion, the frame BLUE should coincide with the frame F1.   MOVE FROB
TO F2 means that  at the end of the motion,   FROB coincides with F2.
There  is a convenience about destinations:  They can be specified in
terms of where  the arm (or  controllable frame) is  at the start  of
the motion.   The symbol for this is ⊗.  That  is, ⊗ is a frame which
is the  location and  orientation of  the controllable  frame at  the
start of the motion.
	Let us  assume for  the sake of  clarity that  an arm is  the
controllable  frame.   Bear in  mind that this  is not  necessary; it
just makes the discussion less wordy.
	There are several  options which may  be used in  conjunction
with  the  MOVE  to  force  certain  things  to  happen.    The  THEN
<statement>  construction tells what  to do if the  move is completed
without error of  any kind.  Due  to the block  nature of HAL,   this
statement can in  fact be itself very complex.
	TRACING is  another  option.   It  allows  the  user  greater
control over  the  exact trajectory  chosen for  the move.   One  can
trace  a  path   at  whatever  speed  one  wants.    The  path,    or
<parameterized frame>,  is a  specification of what frame the arm  is
to go through for each value of  the parameter.  Of course,  one also
specifies  what the relation between the  parameter and real time is.
It  is also  possible  to  state the  grain  of  the motion  and  the
tolerance that is acceptable (as a real distance in 3-space).
	Next  comes  the option  of  MAINTAINING  ORIENTATION.   This
causes the trajectory  computed by HAL  to try to  maintain the  same
hand orientation  throughout the  motion.   It is  required that  the
final  orientation supplied by  the user be  the same  as the initial
orientation for this to work at all.
	The FROM construct  is used  to tell the  compiler where  the
arm is at the moment.  This  should be used if otherwise the compiler
would  have no way  of knowing from  which point it  should begin the
trajectory calculation.
	The VIA list list is  a set of intermediate frames  which the
arm is to pass through.   This may not be used with a TRACING motion.
At each  of  the intermediate  frames,   several  conditions  may  be
specified.   These include velocity,   upper or  lower bounds  on the
time required to  reach this frame from the previous one on the list,
and how the frame is to be  approached and departed.  Also,  using  a
THEN construct,  one can specify some  action which is to be taken at
the  time  this  frame  is  achieved,   such  as  setting  a  flag or
initiating an action for the other arm.  It is  not legal to initiate
action on the arm currently in motion.
	USING lists  a set of modes  under which the motion  is to be
performed.  These  can include  duration control,   force applied  in
some  direction,   which  directions  should  be free  from  position
feedback,  and  what the  departure  and approach  should  be  (if it
desired to override the defaults, which are properties of  the frames
involved at the beginning and end of motion).
	The DURING  field specifies that  another statement is  to be
executed  simultaneously with  this motion.   It can  either have the
statement in  situ,   or  it can  specify the  label  of the  desired
statement (which had better exist somewhere in the program).
	ON requests that  certain conditions be continually monitored
during motion.  These can be  any sort of condition,  including  flag
checking,   force  checking, and  time checking.    If any  monitored
condition  triggers,    the  DO  part  associated  with  it  will  be
executed. This can  include the statement  STOP.  The  implementation
of this will very likely be by means of SAIL events.
	MEANWHILE  specifies some  sort of  statistics request.   The
form of this has yet to be worked out.

	Perhaps something like OCCUPYING <VOLUME> should be added, so
that  some  primitive  compilation-time  collision  avoidance  can be
implemented.
	SIMPLE MOVES
	A move is simple if it involves only one arm.   There are two
varieties  of  move:  MOVE  and  GO.   The  former  causes  a  smooth
trajectory to be  compiled.   The latter lets  the servo  do all  the
calculation, and the arm will stop after each segment of the motion.
	Certain things must be  specified in any move.   First is the
arm which  must be moved.  This can  be specified directly (as YELLOW
or BLUE) or by specifying a frame  which is to be moved.  A FRAME  is
a location with  an orientation.  Wherever the hand  is constitutes a
frame.   YELLOW is a frame.  Certain objects will have frames on them
also. It is  possible to attach frames  to arms.   So if the hand  is
holding a frob,  it  is perfectly reasonable to request that the frob
be moved to a particular  location.  So if  FROB is a frame  attached
to BLUE, then both FROB and BLUE are <controllable frame>s.
	Next, the destination  must be specified.  This  is specified
as a frame, of  course.  MOVE BLUE TO F1 means that at the end of the
motion, the frame BLUE should coincide with the frame F1.   MOVE FROB
TO F2 means that  at the end of the motion,   FROB coincides with F2.
There  is a convenience about destinations:  They can be specified in
terms of where  the arm (or  controllable frame) is  at the start  of
the motion.   The symbol for this is ⊗.  That  is, ⊗ is a frame which
is the  location and  orientation of  the controllable  frame at  the
start of the motion.
	Let us  assume for  the sake of  clarity that  an arm is  the
controllable  frame.   Bear in  mind that this  is not  necessary; it
just makes the discussion less wordy.
	There are several  options which may  be used in  conjunction
with  the  MOVE  to  force  certain  things  to  happen.    The  THEN
<statement>  construction tells what  to do if the  move is completed
without error of  any kind.  Due  to the block  nature of HAL,   this
statement can in  fact be itself very complex.
	TRACING is  another  option.   It  allows  the  user  greater
control over  the  exact trajectory  chosen for  the move.   One  can
trace  a  path   at  whatever  speed  one  wants.    The  path,    or
<parameterized frame>,  is a  specification of what frame the arm  is
to go through for each value of  the parameter.  Of course,  one also
specifies  what the relation between the  parameter and real time is.
It  is also  possible  to  state the  grain  of  the motion  and  the
tolerance that is acceptable (as a real distance in 3-space).
	Next  comes  the option  of  MAINTAINING  ORIENTATION.   This
causes the trajectory  computed by HAL  to try to  maintain the  same
hand orientation  throughout the  motion.   It is  required that  the
final  orientation supplied by  the user be  the same  as the initial
orientation for this to work at all.
	The FROM construct  is used  to tell the  compiler where  the
arm is at the moment.  This  should be used if otherwise the compiler
would  have no way  of knowing from  which point it  should begin the
trajectory calculation.
	The VIA list list is  a set of intermediate frames  which the
arm is to pass through.   This may not be used with a TRACING motion.
At each  of  the intermediate  frames,   several  conditions  may  be
specified.   These include velocity,   upper or  lower bounds  on the
time required to  reach this frame from the previous one on the list,
and how the frame is to be  approached and departed.  Also,  using  a
THEN construct,  one can specify some  action which is to be taken at
the  time  this  frame  is  achieved,   such  as  setting  a  flag or
initiating an action for the other arm.  It is  not legal to initiate
action on the arm currently in motion.
	USING lists  a set of modes  under which the motion  is to be
performed.  These  can include  duration control,   force applied  in
some  direction,   which  directions  should  be free  from  position
feedback,  and  what the  departure  and approach  should  be  (if it
desired to override the defaults, which are properties of  the frames
involved at the beginning and end of motion).
	The DURING  field specifies that  another statement is  to be
executed  simultaneously with  this motion.   It can  either have the
statement in  situ,   or  it can  specify the  label  of the  desired
statement (which had better exist somewhere in the program).
	ON requests that  certain conditions be continually monitored
during motion.  These can be  any sort of condition,  including  flag
checking,   force  checking, and  time checking.    If any  monitored
condition  triggers,    the  DO  part  associated  with  it  will  be
executed. This can  include the statement  STOP.  The  implementation
of this will very likely be by means of SAIL events.
	MEANWHILE  specifies some  sort of  statistics request.   The
form of this has yet to be worked out.

	Perhaps something like OCCUPYING <VOLUME> should be added, so
that  some  primitive  compilation-time  collision  avoidance  can be
implemented.
	SEMANTICS CONTINUED.

	SEARCHES
	A  SEARCH is  very  much like  a  move.   It  is a  means  of
specifying  repeated action  in a  spiral.  As  with a  MOVE,   it is
necessary to name  a controllable frame  which is to  be moved.   The
THEN, FROM, and ON constructs are exactly as they are for MOVEs.
	One must  stipulate what the  plane of  the search is  to be.
This is  accomplished in either of two ways: ACROSS <plane> means the
search is to take place in the plane specified.   If the controllable
frame (say the hand) is in  fact not in that plane at the start, then
the plane parallel to the given one, through the hand, will be  used.
It is assumed that the  hand is already at the center  of the search.
The  other  alternative is  to  say NORMAL_TO  <vector>.    This will
specify the plane you want  for the search. Actually, the servo  does
almost all  the calculating for  this; it is  fed the normal  and the
increment size.
	Most  important for  the search  is the  REPEATING construct.
It is by this  that one specifies what  motion is to be  performed at
each iteration of the search.   It is advisable that the motion cause
the arm to return to the point at which it began, in order to  assume
the same plane at the onset of each iteration.   If this is not done,
then the  servo will move it back each time  anyway.  When the search
succeeds (and it  is the  duty of  the user to  specify what  success
means for each search) the search  can be terminated in either of two
ways:  by setting a flag in the REPEATING  and checking it in the ON,
or by using the construct DONE inside the DURING  at the right place.
Note that  the DONE must have the  label of the SEARCH,   not that of
the MOVE.

	RUN-TIME MODIFICATION OF TRAJECTORIES
	All trajectories are modified before  execution to bring them
into  line with  current values  of  frames.   After every  move, the
run-time location of the hand is determined, and all frames  fixed to
it are updated; if there is  any discrepancy between the run-time and
compile-time  understanding of where the frame  is, the servo will go
the the  right place  nonetheless.   The ASSUME  statement tells  the
compiler where it should expect the frame to be.

	CENTER
	It happens  at times that  the hand  is positioned around  an
object, and  it is desired to  center the hand around  it,  and close
the fingers at the same time.   This is accomplished by means of  the
CENTER command.  As with the SEARCH command,  it takes as an argument
the  plane in which  the centering is  to take place,   either by the
construct   ACROSS  <plane>   or   by   NORMAL_TO  <vector>.      The
specifications of  DURING,  THEN,   and ON  are just as  in a search.
More complex centering actions can  be added when more  sophisticated
touch sensing is added.  Some such actions can  be done as it stands;
the  ON construct  is used to  add an  offset to the  trajectory upon
touch or force  sensing.  The  ADD construct has  not yet been  fully
worked out.

	DRIVE
	If it is desired  to drive only  one joint at  a time, or  to
explicity control several joints at once, the way  to do this is with
a DRIVE.   The particular joint is  specified, as is the destination.
In this context,  ⊗ means  the current  location of this  joint,   in
radians  (or inches).    As for  a  simple move,  it  is possible  to
specify  the  exact  nature  of the  motion  by  means  of  a TRACING
construct.  To  get several  joints going in  unison, use the  DURING
construct.   The other options are  just as in MOVE.   It is expected
that this will only be used for arm maintenance and testing.

	WORLDS
	A world is a collection of  defined objects, frames, vectors,
etcetera, along with  their values and structure of attachment.  When
a world is saved,   all this information is  written out on the  disk
somewhere.  When it is restored, the compiler picks up its version of
the  world,  and generates code for  the servo to reload its version.
The purpose  of this is  to provide safe  places in  the HAL code  at
which one  can stop for the night,   or to which one  can return upon
failure of some experimental  code.  Note that  no provision is  made
for the real world to be restored; this is up to the user.
SOME SAMPLES OF HAL CODE, WHICH DEMONSTRATE THE SYNTAX

IF L THEN BEGIN OUTSTR("SOMETHING WRONG"); SCREW(-20) UNTIL TORQUE(Z)>10 END
ELSE
M1: MOVE YELLOW
	TO C THEN BEGIN Q ← TRUE; T←T+1; ATTACH A TO YELLOW; STOP BLUE END
	VIA B:VEL=A1, D:DURATION≥20 THEN Q←FALSE
	USING DURATION≥20, FORCE=M*3, FREE=(T,V), APPROACH=(0,0,U)
	DURING SCREW(60)
	ON VEL(1)>40 DO ER←2,  TORQUE(Z)>50 DO STOP,  P= TRUE DO
		BEGIN P←FALSE; GOTO M2 END  comment: 3 conditions checked;

to do a box search:

M10:  SEARCH YELLOW
	PLANE P comment: will take plane parallel to P through current hand;
	INCREMENT .1
	REPEATING 
		BEGIN  "PROBE"
		GO YELLOW
			TO ⊗ + .1*Z
			ON FORCE(Z)>20 DO DONE
		END

To turn a  crank of radius R, assuming  it lies in the X-Y  plane and
that the hand is holding the crank at (R,0) in that plane:

MOVE YELLOW
	TRACING
		LOC = (R*COS(β), R*SIN(β),0) + ⊗ - (R, 0, 0),
		ORIENT = ORIENT(⊗),
		FOR β ← 0 BY .1 UNTIL 2*PI
	MAINTAINING FREE(@ - (⊗ - (R, 0, 0)))

To lift  a wrench held by both arms, straight up 10 inches:

MOVE {YELLOW, BLUE}
	TRACING
	 LOC.YELLOW = ⊗.YELLOW + β*Z,
	 LOC.BLUE = @.YELLOW + ⊗.BLUE - ⊗.YELLOW,
	 ORIENT.BLUE = ORIENT(⊗.BLUE),
	 ORIENT.YELLOW = ORIENT(⊗.YELLOW),
	 FOR β ← 0 BY .1 UNTIL 10
	MAINTAINING FREE.BLUE(@.YELLOW - @.BLUE)
COMPLEX MOVES.

The  following are  some  random  thoughts  concerning what  sort  of
coordination is needed between two cooperating arms.

Time coordination:  Independent trajectories,  but some control  over
when  each achieves  its objectives.   This can  be done  entirely by
simple moves  using the  DURING or  COBEGIN  constructs and  suitable
state variables.

Space  coordination:  This  inherently  requires  some  sort  of time
coordination as  well. It  is perhaps best  to consider  the arms  in
question as one device, with  say 12 joints,  and a trajectory should
be created accordingly.

Here is  a  rough idea  on  how to  truly coordinate  two  arms in  a
non-TRACE  type trajectory.    Say we  want a  regular  trajectory to
location B for the yellow, and we want the blue to maintain  the same
relation to yellow as  it now has.  Note that if  the purpose of this
is  to heft  a heavy  frob,   the orientations  of the two  hands had
better remain the same, and the current orientation must  be the same
as at frame B.
	This brings  up an important point.   For coordinated motions
(as well as  for some simple  moves) it is  desirable to specify  the
orientations throughout  the motion.   TRACE  allows (nay,   demands)
this.  MOVE should also allow it.

MOVE {YELLOW, BLUE}
	TO {B, *}
	COORDINATING LOC.BLUE = LOC.YELLOW + ⊗.BLUE - ⊗.YELLOW
	MAINTAINING FREE.BLUE(@.YELLOW - @.BLUE)
	MAINTAINING ORIENT = {ORIENT(⊗), ORIENT(⊗)};

	Some  space coordination can be  achieved by specifying moves
in both  arms  and  demanding  that certain  intermediate  points  be
achieved in  time unison.   This could  be done either  by explicitly
specifying  the time  for  each segment  or by  using a  combined VIA
list, of the form 
	VIA {AYEL,ABLU},{BYEL,BBLU}, etc.

	The   construct  of   COBEGIN   is  meant   for   independent
simultaneous  motion.  Each of  the statements in the  block is begun
more or less  simultanously; the  block is not  terminated until  the
slowest statement has finished.  There are a few restrictions to such
a block:  None of the statements may be labeled (for it is illegal to
jump into  the  block); there  must be  no GOTOs  in  the block,  the
devices used  by the statements must  be disjoint (there  must not be
simultanous use of  the blue  arm by  two statements);  some sort  of
space-used checking will very  likely be implemented,  and  a warning
printed upon compilation if a collision is possible.

Collision avoidance:
	Use of  two  arms severely  worsens  the complexity  of  this
problem,   which even  in the simpler  case of  one arm has  not been
systematically (or even seriously) attacked.
	One method  that has  been suggested  is to  consider all  of
space-time divided up into  regions of suitable size.   These regions
are to  be regarded as resources which allow  only one user.  Several
difficulties with  this  approach:  1)  There would  be  an  enormous
amount of overhead in checking which  resources a given move uses. 2)
Having  discovered  that  a  calculated  trajectory  enters forbidden
territory,   it  is  not at  all  clear what  to  do to  correct  the
trajectory  to   avoid  it.     Some  modification  of   the  current
table-avoiding system might be usable. In any case,  it would not  be
discovered that  there is any  difficulty until after  the trajectory
has  been calculated.  This  is itself an expensive  calculation.  3)
Some trajectory calculations  will perforce be  left until run  time.
In the run-time  environment, it will be very difficult  to do checks
on  resources. Note:  there  is serious  objection to  any trajectory
calculation during run time.

The following is derived  from the ideas in  the JPL paper at  the AI
conference.

Let there  be a  new datatype,   type FREEWAY.   It is a  sequence of
frames along which the arm is to be allowed to travel.  The  sequence
is computed to  avoid explicitly stated and default  obstacles (which
can include other stated freeways).  Here is an example:
	FREEWAY F1, F2, F3;
	FRAME A, B, C, D, E, F;
	 code to set up the frames;
	PAVE F1 FOR BLUE FROM A TO C VIA B;
	PAVE F3 FOR BLUE FROM A TO B AVOIDING F WITH RADIUS=5;
	PAVE F2 FOR YELLOW FROM D TO E AVOIDING F1, F3;
	
	MOVE BLUE TO C 
	ALONG F1
	 DURING BEGIN MOVE YELLOW TO E ALONG F2 END;

	Whenever a  freeway is paved (as opposed  to declared), it is
checked against those obstacles which it must avoid. The paving  of a
freeway  will also  compute trajectories  along its  length.   When a
motion  is performed  along  a freeway,   the  motion will  enter the
freeway as soon as  possible and will stay on  it as long as  it can.
Perhaps the servo will  control automatically the entrances and exits
as errors to preplanned trajectories.
	If it  is not  possible to  pave  a new  freeway due  to  the
proximity  of another  paved freeway,    an attempt  can  be made  to
reroute  the conflicting  freeway,   maintaining,   of  course,   the
constraints under it was first paved.

	Freeway paving is very expensive,  for it  involves extensive
calculations. It is recommended that  all paving be done with respect
to  stable variables.   Paving  through fuzzy  points is  most likely
pretty safe too.  

	There are esthetic  objections to freeways. Therefore,  until
overwhelming  indication  to the  contrary  arises,  we will  perform
collision avoidance solely  by means  of VIA  lists, thereby  putting
the responsibility for  collision avoidance squarely on  the shoulder
of the user.
TYPES OF VARIABLES.

	SCALAR Used for times, angles, etc.  The units being used are
dependent on the  UNITS statement, which tells the compiler that when
a time, say, is required, the scalar is to be interpreted in jiffies;
when a  distance is needed,  the scalar is  in meters.   The defaults
have not been decided; suggestions are welcome.  Note that inside the
compiler, and inside  the runtime, all  measurements will be in  some
uniform system, most likely centimeters, milliseconds, grams.  

	A PARAMETER is a variable which can be bound to a scalar, but
is usually used only in a partially constrained sense.  An example is
"x where x ≥ 3".   The constraints on  parameters may be in terms  of
other parameters, such  as "where x+y=4".  The  purpose of parameters
is  to be  able to  specify scalars  (and hence vectors,  frames, and
transforms) in an  incomplete way.  Thus  a legal vector constant  is
"(3 x y) WHERE x-y>5".

	A VECTOR is an ordered triple of  reals specifying a directed
distance wrt a given  frame.  Default is table frame.  Vectors may be
fixed to a frame.  This is the usual case for vectors defined wrt any
frame other than the table.  It  is possible to have a "free" vector,
that is it takes on meaning only when used in a calculation, and then
assumes the  frame of the  object to  which it  is arithmefied.   The
vector  constant is (s  s s)  where s is  a scalar  expression (which
includes expressions using parameters).  This can be taken to mean  a
translation (in x, y, z of the frame by which this vector is defined)
or  a rotation  (in whatever  mode of  angles currently  being used).
Standard forms  for rotations are  Euler angles  (rotations about  z,
x', z''), Bolles angles (rotations about x,  y, z), and Taylor angles
(z,  x',  y').  Geomed  angles are different: (a,   b,  c) where this
specifies the vector of rotation,  and the magnitude  is the angle of
rotation.   Since   the   internal  representation   is   (hopefully)
independent of which idea is meant, there should be no trouble.

	A FRAME is a location with an orientation.  It has two  basic
interpretations,   which are  really the  same.   It can  be used  to
specify a  hand position,  and it can be  used to define the location
and orientation of any object. The default frame of reference  is the
table coordinates.  New frames are  defined wrt old frames.  They are
described  by  a  pair  of vectors:  one  for  position  and  one for
orientation. The constant is v≡v  where v1 is the location and  v2 is
the orientation.  Frames also have an optional deproach (which is six
numbers,  for location and orientation  wrt the frame itself) and  an
optional mass.   FRAMEs can be  declared FIXed to another  frame (not
necessarily  the one via  which they  were specified).   Whenever the
value of a FRAME changes,  all the frames and vectors which are fixed
to it  are automatically updated,   both at  compile time and  at run
time.   Thus a frob held in the hand  can have its frame fixed to the
hand frame.  If the hand moves, so does the frob frame.

	A  TRANS is a device  for moving a vector or frame elsewhere.

	A PLANE is  a vector,   which specifies the  normal direction
and the distance of the plane from the origin.

	An ATOM is an entity consisting of a  set of properties.  The
properties  can themselves  be atoms, lists  of atoms,  or arithmetic
constants.   The type of  any property  must be  declared before  the
property is used, or  some default will be selected.   There is a set
of  standard properties  assosiated  with each  object atom;  see the
later page  discussing  this. As  in LISP,  there  are mechanisms  to
accomplish  these manipulations:  (1) Add  a new  property  or change
current  value:  propname(atom)  ←  value.  (2)  Delete  a  property:
propname(atom) ← NULL.  (3) Reference a  property.  propname(atom) is
the expression  which has the desired value.   In all these, propname
must  have been  declared,  eg:  SCALAR  LIST  PROPERTY  X,Y;  VECTOR
PROPERTY LENGTH; ATOM LIST PROPERTY DESCENDENTS.
ARITHMETIC.

`s' = scalar or parameter, `v' = vector , `f' = frame,
	`p' = plane, `t' = trans.

frame expressions:

v ≡ v		v1 is a location, v2 is an orentation
f + v		v is a translation
f ∂ v		v is a rotation
f +← v		v is a location which is munged into f.
f ∂← v		v is an orientation which is munged into f.
t * f
s * f		moves away from table origin
∀ f		deferred frame

trans expressions:

f → f		how to get from f1 to f2
v | v		v1 is a translation, v2 is a rotation
t + v		v is a translation
t ∂ v		v is a rotation
t * t
t +← v		v is a translation
t ∂← v		v is a rotation
∀ t		deferred trans

vector expressions:

v + v		v2 is a translation
v ∂ v		v2 is a rotation
t * v
v . v		dot product
f - f		difference wrt location ( a translation )
f / f		difference wrt orientation ( a rotation )
s * v		dilation
∀ v		deferred vector

plane expressons:

p + v		v is a translation
p ∂ v		v is a rotation
t * p
s * p		moves away from the origin
∀ p		deferred plane

scalar expressions:

s + s
s * s
s - s
s / s
|v|		magnitude of v
∀ s		deferred scalar



Predefined constants and variables:
⊗ is the location of the arm at start of motion.
@ is the location of the arm at time of evalutation, which is
	assumed to be continuous during motion.
XVECT(FRAME) is a unit X vector in FRAME.  Default FRAME is TABLE.
YVECT(FRAME) is a unit Y vector in FRAME.  Default FRAME is TABLE.
ZVECT(FRAME) is a unit Z vector in FRAME.  Default FRAME is TABLE.
XSCAL(FRAME,VECTOR) is the X-coordinate of the vector as seen from the frame.
YSCAL(FRAME,VECTOR) is the Y-coordinate of the vector as seen from the frame.
ZSCAL(FRAME,VECTOR) is the Z-coordinate of the vector as seen from the frame.
TABLE is a frame which has standard table coordinates.

A LIST OF CONTINUOUSLY EVALUATED FUNCTIONS:
	TORQUE: VECTOR → REAL  
	FORCE:  VECTOR → REAL  
	DISTANCE(<FRAME>,<FRAME>)  This is the distance between the
two frames.  If one of the frames is an arm, then this means the closest
distance.

DEFERRED EVALUATION
	This  is  a  discussion  of  the   syntax  and  semantics  of
expressions.  In every  case, we  describe  the compile-time  and the
run-time effects of the statement containing the expression.
	The most  straightforward kind  is the  following:  To set  a
value in a frame: FROB  ← (3 2 0) ≡ (0 π 0)  will just put that value
into  FROB,  and generate  code  which  loads the  constant  into the
runtime cell reseved for FROB.
	Slightly more complicated:  NEWFROB ← FROB  + (1 3 2)  Causes
immediate compile-time calculation of  NEWFROB for the benefit of the
compiler, and generates  code which  will take the  current value  of
FROB and  do the appropriate  arithmetic, storing  the result in  the
cell for NEWFROB.
	Even more complicted: FIXEDFROB ← ∀ FROB + (1 3 2) The symbol
∀ is  a  unary operator  by syntax,  and  means "always".  It  causes
evaluation  of  its  argument  to  be  postponed  until  needed.  The
generated  code is the same as for  the previous case, but every time
the value of FROB is changed, code will be generated to appropriately
change FIXEDFROB.   In this case,  the updating will  be a "position"
updating only.  It is also possible to cause an "orientation  update"
only.  An  example of this is  FIXEDFROB ← ∀ FROB  ∂ (0 π π/2).   The
third  simple case is a  "complete update", caused  by something like
FIXEDFROB ← ∀ FROB  * (A→B).   Any more compilicated expression  will
cause each change in FROB to generate explicit code for the update of
FIXEDFROB.
	If  FIXEDFROB is, say, the endpoint  of some trajectory, then
it will be evaluated at trajectory-planning time on the  basis of the
current (compile-time) version of  FROB.  At run-time, the trajectory
will be modified  to bring  it in  line with  the current  (run-time)
version of FROB.  

	The  above discussion  applies equally  well  to vectors  and
planes.

	When the  statement ATTACH FROB TO BASE  occurs, this has the
same effect  as the  statement  FROB ←  (BASE→FROB) *  ∀ BASE.    The
statement  DETACH  FROB  has  the  effect  of  causing  all  deferred
evaluations  to  be carried  out, and  the  resulting constant  to be
assigned to FROB.  No code is generated.
	In order to set FROB to, say, (a b c)≡(w α β) with respect to
PUMPBASE,  one can say  FROB ←  (A B C)≡(W  α β)  * (TABLE→PUMPBASE).
Since this is a bit wordy, the construct PUMPBASE can be used instead
of  TABLE→PUMPBASE  whenever  a  trans  expression  is  unambiguously
required.
DATA STRUCTURES FOR REPRESENTATION OF OBJECTS.

New datatype: ATOM.  Consists of property list.  Each property has
a name, depending on what kind of atom it is.

OBJECT ATOM: all the knowledge needed about a (possibly hypothetical) object.
	LOCATION 	(LOCATION ATOM)
	MASS		(SCONST)
	MOMENT1		(VCONST)
	MOMENT2		(VCONST)
	STABILITIES	(LIST OF STABILITY ATOMS) 
	GRASPS		(LIST OF GRASP ATOMS)
	SUBPARTS	(LIST OF OBJECT ATOMS)
	USER-DEFINED	(anything whatsoever)
	AFFIXION	(OBJECT ATOM) to whom this object is affixed.

LOCATION ATOM:  where something is.
	LOCUS-FORM	(FEXP) may be parameterised.
	DETERMINATION	(FEXP) represents what is known about locus.
	NOMINAL VALUE	(FCONST) usually centroid of locus-form.

STABILITY ATOM: how the object can safely rest.
	LOCATION	(FCONST) with respect to the locus-form.
	FOOTPRINT	(FCONST) of a coffee cup looks like a dunce+cap.
	GRASPS		(LIST OF GRASP ATOMS) only those allowed from this spot.
	
GRASP ATOM:  where to grab object.
	OPENING		(SCONST)
	DEPROACH	(FCONST)
	HANDSHAKE	(SCONST) how hard may grasp without mauling.
	STABILITIES	(LIST OF STABILITY ATOMS) only those at which this grasp legal.
COMPILE TIME AND RUNTIME MODIFICATION OF VARIABLES

→→→→→→this page is currently undergoing change.  It is wrong.

	The  question arises  concerning  what to  do  if the  actual
location of a  frame is not exactly the same as its planned location.
Say that  the  actual location  has been  determined  by means  of  a
search.  What one  wants to do is to say, "whenever I  say FROB, I no
longer  mean my planned FROB,   but rather the FROB  that I have just
located." This can be done by the following code:
	FROB ← <some calculations based on hand position>
The effect of this is to cause the runtime  program to read the hand,
do  the calculations,  and modify  the cell for FROB  so that
future trajectories using FROB  will be appropriately modified.

	ASSUME FROB AT <some frame expression, possibly depending on hand>
The effect of this is  to cause the compiler to modify  its world.
No code is generated.

	Now the big question: what does all this  gain us?  It allows
us to plan trajectories even when we knw that the actual locations we
are using are somewhat  suspect.  It  renders the system tolerant  to
location errors.  Exactly how tolerant is a matter for investigation.
If  the  servo tries  to  run a  trajectory which  has  been slightly
modified (say less  than 10 centimeters),  the chances are good  that
nothing  bad  will happen.    As the  correction  grows, though,  the
following bad effects begin to appear:
1) The timing is off.  Not enough time  to move the arm the requisite
distance.  The arm moves too fast.
2) The careful avoidance  of collisions goes to waste;  the margin of
clearance becomes negative.
3) The  selection of which  joints are  to be free,  and which are  to
sense  force becomes wrong (this  selection is currently  not made at
runtime); even  before this,  the quantitative  measurement of  force
becomes innacurate.
4)	The arm tries to go past its stops.
CONTROL STRUCTURES.

The overall outline of the program is this:
	A set of declarations followed by a set of statements.

Statements can cause the  execution of other statements out  of line,
by means of the EXECUTE subcommand.

It  is envisioned that most  statements will have labels  and will be
treated  as  subroutines.    There  will  also  be   procedures  with
parameters, as well as macros.  Block structure will be implemented.

The major problems seem to be these:
	1) The  status of variables  will change at run  time between
stable  and instable.   Trajectory  calculations will be  possible at
compile time only for  stable or fuzzy variables;  other calculations
must be  deferred until the  requisite variables are  at least fuzzy.
Some of this run-time scheduling of computation should be managed  by
the run-time  routines, but  some must  perforce be under  programmer
control.
	2)  In  iterations,   the  variables  used  may change  their
status.  That is, the compiler  may never know whether a variable  is
to be taken as fixed, unless it is explicitly told.

Recursion may  be a nice feature.   For example, programming  the arm
to  solve the Tower of Hanoi problem  requires recursion.  This opens
an  entire  box of  difficulties  concerning  saving  old  values  of
variables for later restoration upon recursive ascent.

Some forms of  iteration, at least,  must be  implemented.  I suggest
the following constructs:
	WHILE <boolean> DO <statements>
	FOR <control id> ← <arith expr> [STEP <arith expr>] UNTIL
	 <arith expr>
	DO <statements>
	IF <BOOL> THEN <STATEMENT> [ELSE <STATEMENT>]
	GOTO <label> {uggh!}
	EXECUTE <label> {Like a F0RTRAN CALL}
	DONE {Terminate loop.  This can also be used to terminate a
	 MOVE}
	CONTINUE {Terminate this iteration; continue the loop}

SAIL -  type forks  and joins  for disassociating  truly  independent
motions should be included as an alternative  to the DURING notation.
The syntax for these has not yet been worked out.
IDEAS WHICH MUST BE THOUGHT OUT.  THEIR TIME HAS ALMOST COME.

Should there  be a  datatype OBJECT?   What sort  of fields would  it
have?  How would it  be related  to frames? STANDARD  DESCRIPTIONS OF
OBJECTS SHOULD IN SOME WAY BE COMPATIBLE. IT SHOULD NOT  BE NECESSARY
FOR  STRATEGY PROGRAMS  TO CONTORT  THEIR USUAL  WAY OF  REPRESENTING
OBJECTS.   →→→→→This  might  be getting  into more  model-based stuff
than we want.  -- RF

PERHAPS STANDARD APPROACH SHOULD  BE AN OPTIONAL PROPERTY  OF FRAMES.
THIS THEN IS  THE DEFAULT WHEN NO EXPLICIT  APPROACH OR DEPARTURE ARE
MENTIONED.  THE APPROACH  FOR THE FRAME "TABLE"  SHOULD THEN BE (0  0
3). →→→→→I think this is a good idea.  Any takers?

HAL SHOULD BE IN SOME SENSE A MONITOR  CAPABLE OF COMPILING,  SAVING,
EDITING,   TESTING,   AND  LINKING PROCEDURES,   WITH  DIAGNOSTICS TO
CONSOLE FOR EACH PHASE.

For the sake  of consistency,   it would be  good to have  arithmetic
operators which effect the rotation of  frames.  How could we specify
a  rotation?  Of course,   the methods  already described (ie Bolles,
Euler, and Finkel angles) can be used.  Do we need more flexibility?

OTHER PROPERTIES OF FRAMES:
	SUCH AS STANDARD APPROACH/DEPARTURES, OBJECT MASSES, AXES OF
	 INSERTION AND PERHAPS PROGRAMMER-DEFINED PROPERTIES.
	THE FIXING OF ONE FRAME TO ANOTHER SHOULD DO THE RIGHT
	 THINGS FOR MASS, WHATEVER THEY MIGHT BE.

IT SHOULD BE  POSSIBLE TO  REPEATEDLY FIX AND  UNFIX FRAMES TO  OTHER
FRAMES. Say the yellow has moved  to frame FROB.  Say HOLE is a frame
fixed to FROB. Say we  want to move the  frob so HOLE coincides  with
frame HOLESPOT.  Use the following code:
	ATTACH FROB TO YELLOW;
	MOVE HOLE TO HOLESPOT;
	 COMMENT: Since HOLE is fixed to FROB, which is now attached
	 to YELLOW, this command is translated into a motion
	 for the yellow hand; 

An alternative fomulation might be:
	ATTACH FROB TO YELLOW;
	MOVE YELLOW TO (SUCH THAT HOLE=HOLESPOT);

Note  the interesting  consequences  of  attaching  one hand  to  the
other.   Then  a motion of  one hand  forces the  other to move  in a
coordinated way. I guess it even forces the orientations to  come out
right.
THE FOLLOWING PAGES ARE FOR COMMENTS & COMPLAINTS BY POTENTIAL USERS.
	...	SAMPLE PROGRAM : SLIP_OVER  (OCT 10)

A sample program (or piece thereof):

	...... in the main program  ......
    INTEGER K, STATUS;
    FRAME (DEF_WRT TABLE) CLUTCH_SLEEVE;
    FRAME (DEF_WRT CLUTCH_SLEEVE) SLEEVE_HOLE;
	PRELOAD_WITH (EULER 0,0,0,0,0, 1.6);  COMMENT preloads frame above;
    FRAME ROLLER_BEARING;  COMMENT if no `WRT' is stated, the default is 
				the TABLE frame (or default could be set);
    FRAME PS_SUBASSEMBLY;
	FRAME (FIXDEF_WRT PS_SUBASSEMBLY) CLUTCH_END;
		PRELOAD_WITH (BOLLES 180,0,0, 0,0,2.92);
    FRAME (FIXDEF_WRT PS_SUBASSEMBLY) FLYWHEEL_END;
	PRELOAD_WITH (EULER 0,0,0,  0,0,-2.86);

			.
			.
			.
MACRO SLIP_OVER(FRAME SHFT_END;  FRAME SLEEVE_HOLE;
		REAL MAX_DIST;
		REAL DISTANCE_TO_MAIN_SHAFT;
		REAL STEP_DISTANCE; INTEGER NUMBER_OF_STEPS;
					REAL STEP_STOPPING_FORCE;
		REAL FINAL_STEP, FINAL_STOPPING_FORCE);
    BEGIN COMMENT assume the yellow hand has already picked up the `sleeve' 
		to be slipped over the `shaft' ... and attached it to the hand.
		the steps are:
	    (1) move the sleeve so that it is aligned with the shaft and is just
		off the end of the shaft
	    (2) search to slip the sleeve over the end ... just a little way
	    (3) slip onto main shaft ... not stopping on force, but checking time
	    (4) loop to slide along the shaft in a number of steps
	    (5) a final push against the end (if FINAL_STEP>0.0);


    COMMENT step 1 ... move close to end of shaft;
	MOVE SLEEVE_HOLE TO SHAFT_END - .2*Z.SHAFT_END;
		COMMENT Z.**** is a predefined construction which produces
		    a unit vector in the Z direction of the indicated frame;
	    USING APPROACH (-3*Z.SHAFT_END);	

    COMMENT step 2 ... search to slip over a little;
	SEARCH YELLOW
	    AROUND SHAFT_END   COMMENT meaning to search in the X-Y plane of frame;
	    INCREMENT  .2
	    ON (FORCE(Z.SHAFT_END) > MINIMUM(Z.SHAFT_END)+20)  DO GOTO STEP_3;
	    ON (DISTANCE_FROM_START > MAX_DIST) DO
				BEGIN OUTPUT("FAILED TO SLIP OVER AT ALL");
				    STATUS ← 2; COMMENT global flag-like variable;
				    STOP;
				END;
	    COMMENT thus the search continues until one of the ON criteria is
		satisfied ... could have a variety possible eg.
		ON (NUMBER_OF_SEARCH_STEPS > 16) DO ....    ;

    COMMENT step 3 ... slip onto main shaft ... hopefully;
STEP3:	MOVE TO ⊗+DISTANCE_TO_MAIN_SHAFT*Z.SHAFT_END
	    USING FREE(X.SHAFT_END, Y.SHAFT_END)
	    ON (TIME > 60) DO BEGIN OUTPUT("OUT OF TIME GOING TO MAIN");
					 STATUS ← 3;
					 RETURN;
				   END;

    COMMENT step 4 ... slipping along the shaft  ... in N steps;
	FOR K ← 1 STEP 1 UNTIL NUMBER_OF_STEPS DO
	    MOVE TO ⊗+[0, 0, STEP_DISTANCE] WRT SHAFT_END;  COMMENT just another
					way of stating "STEP_DISTANCE*Z.SHAFT_END";
		USING FREE(X.SHAFT_END, Y.SHAFT_END);
		ON FORCE(Z.SHAFT_END) > 100 DO BEGIN OUTPUT("STUCK ALONG SHAFT");
							STATUS ← 4;
							RETURN;
						END;

    COMMENT step 5 ... giving it the final push;
	IF FINAL_STEP > 0.0 THEN
	    MOVE TO ⊗ + FINAL_STEP*Z.SHAFT_END
		USING FREE(X.SHAFT_END, Y.SHAFT_END)
		ON FORCE(Z.SHAFT_END) > FINAL_STOPPING_FORCE DO RETURN;
	OUTPUT("DIDN'T REACH FORCE ON THE FINAL PUSH");
	STATUS ← 5;
	RETURN;
END "SLIP_OVER";



		.
		.
		.
	PICKUP(CLUTCH_SLEEVE ...
	SLIP_OVER(CLUTCH_END, ...
	...	SAMPLE PROGRAM : PUT_PISTON_IN_VISE   (OCT 12)
→→→→→REVISED AS TO SYNTAX 11/3/73

... global definitions ...
    FRAME PS_SUBASS;  COMMENT THIS IS DEFINED WRT TABLE BY DEFAULT;
    FRAME (FIXDEF_WRT PS_SUBASS) CLUTCH_END;
	PRELOAD_WITH BOLLES(-2.86, 0, 0,   0, -90, 0);
    FRAME (FIXDEF_WRT PS_SUBASS) FLYWHEEL_END;
	PRELOAD_WITH BOLLES(2.96, 0, 0,    0, 90, 0);
    FRAME (FIXDEF_WRT PS_SUBASS) CAP;
	PRELOAD_WITH BOLLES(0, 0, .6,      0. 180., 0);
    VECTOR (FIXDEF_WRT PS_SUBASS) SHAFTV;
	PRE_LOAD_WITH [1, 0, 0];

FRAME VISE;  COMMENT assumed to be wrt(table);
VECTOR SHFT, PREDICTED_C_END;
FRAME T_CAP, F_END, C_END, PRE_C_END;
REAL A;
INTEGER I;




PROCEDURE PUT_PISTON_IN_VISE;
    BEGIN COMMENT assume the hand has already picked up the piston at position
	`cap' on the PS_SUBASS ... this procedure puts subassembly into the
	vise,  feels the flywheel end, uses its position to prodict the position
	of the clutch_end, then feel the clutch_end, use the two end locations
	to determine the location of the shaft, update the location of the 
	subassembly (reset its frame value) ...;

	MOVE YELLOW
	    TO VISE + [0, 0, 1.0];  COMMENT correction for hand above vise;
	    USING APPROACH([0, -3, 0] WRT VISE, MAX_VELOCITY=SLOW?
	CLOSE_VISE
	    ON (VISE_OPENING < 1) DO 
			BEGIN OUTPUT("PS_SUBASS NOT GRIPPED BY VISE???");
				RETURN;
			END;
	OPEN 3;
	CENTER 
	    ON (GRASP < .4) DO STOP;
	T_CAP ← @; COMMENT save the current location for future computing;
	FEEL_POINT(3, [3,-3,3], 3, FSA, SHFT3, FSA, 90);
	    COMMENT this routine feels the flywheel end twice ... and saves
		resulting location in F_END for further computation;
	SHFT ← (XYZ[T_CAP] - [0, 0, .6]) - XYZ(F_END);
	    COMMENT seems nicer to directly say XYZ(<FRAME>) rather than
		table↓t_cap    ...   this statement computes a vector along shaft;
	SHFT ← SHFT/LENGTH(SHFT);  COMMENT makes SHFT  a unit vector
		maybe we should have UNIT(...), LENGTH(...), as built-in fns;
	PREDICTED_C_END ← XYZ(T_CAP) + 2.86*SHFT;
	PRE_C_END ← T_CAP - [0, 0, .6] + PREDICTED_C_END;  COMMENT this is the
		place where the hand is going to feel for the clutch end ...
		all of this computation could be done in one statement:
		PRE_C_END ← (T_CAP - [0,0,.6]) + 2.86*UNIT(XYZ(T_CAP-[0,0,.6])-
							XYZ(F_END));
	A ← -.1;
	I ← 0;  COMMENT increment for loop;
	WHILE (I ≤ 4) DO
	    BEGIN
		OPEN 3;
		MOVE TO PRE_C_END + [0, 0, I*A];
		CENTER ON SUCCESS DO DONE "LOOP";
		I ← I + 1;
		A ← (-1)*A;
	    END;
	IF I = 5 THEN BEGIN OUTPUT("CAN'T FIND THE CLUTCH END");
				RETURN;
		      END;
	COMMENT this seems clumsy ... want a loop with two possible exits
	    (1) tried all possibilities and none worked
	    (2) found one that worked 
	  and of course want to do two different things ... GOTO's might
	  make it more readable ... ???
	→→→→→I CHANGED IT A TRIFLE.  BETTER?  --RF 11/3/73
	C_END ← @;  COMMENT now have both ends ... C_END & F_END;

	COMMENT compute a unit vector along the shaft: SHAFTV
	    DON'T have to compute SHAFTV ... define it fixed wrt PS_SUBASS
	    update the position of the PS_SUBASS ... probably by calling
	    another procedure or possibly sending messages to a hairy prog
	    which updates frames, given points on planes, points=points, etc.;

	UPDATE(PS_SUBASS, T_CAP, C_END, F_END);
    END OF PUT_PISTON_IN_VISE;
	...	A REWORK OF PUT_PISTON_IN_VISE (W/ SETS, RESTORES ...NOV 6)

...first a macro for feeling a point ... ie. move to the point,
	center, save discrepency, rotate some number of degrees,
	center again, save discrepency ... hopefully by then you
	have a good estimate of where the point is (ie. you have
	produced a restoring trnasform which moves the planned position
	for the point to a `better' estimate of the position for the point)
	...used to improve the location of end of the shaft ... used to
	improve the location of a bolt, pin, valve opening, etc.

...consider the following "attach" structure of frames ...
	TABLE
	    YELLOW
		FROB
		    FROB_HOLE
		    FROB_GRASP
	    BLUE
	    BEAM
		BEAM_HOLE

...thinking about the following instructions and ideas:
	every frame can have an `automatic restore' associated with it ...
	this means that each time that frame is referenced, the compiler
	should check to see if it has (ie. needs) such a restore, if so
	the compiler should generate code to use it ... it also seems
	reasonable to set this up so that if frames are attached to
	each other, and if one frame has an auto restore, then anything
	`under' it in the attachment structure should also be automatically
	restored ... eg. if FROB has an auto restore, then the use of
	FROB_HOLE should be autoamtically updated too.  What about frames
	above it in the attach structure ... probably not automatically
	updated ... finding a better estimate for FROB may not tell you
	anything about the position of the yellow hand even though
	the FROB is being held in the hand ... the grasping position may
	not be known very well ... 
	SET FROB_HOLE → BEAM_HOLE  ... would set up a transform which
	    modifies the planned position of FROB_HOLE to the actual
	    position of BEAM_HOLE (which could have auto restore too)
	... if you want the setting of FROB_HOLE to set the position
	    for the whole FROB, use a statement like:
		SET FROB BY FROB_HOLE → BEAM_HOLE
	question ... what if FROB_HOLE has an automatic restore and
	FROB is set?   shouldn't the FROB_HOLE lose its auto restore?
	MAY not want this if at run time it has been determined that
	this FROB has its hole in a slightly different relative position
	than usual ... this would require  the compiler to tack on
	a string of auto restores ... one for FROB and one for FROB_HOLE ...

	how does this relate to run-time calculations based upon FROB
	FROB_HOLE, etc.??? at run-time certainly want best postional info
	presumably any position computed and used at run-time must be
	approximated at compile-time so the compiler has some clue
	where things are going to happen ... this seems to imply that
	any modifications at run time have to be done by SETS and RESTORES
	UNLESS ... servo can calculate things for you ... maybe GOs and GOTOs.


	not sure what auto restores do if frame is sent to a procedure
	may need an ASSUME FRAME AT (...) to give compiler something to
	use as a mental picture for compiling ...

	for regular restores may want SAVE F1→F2 IN T,  RESTORE T  

	all of this is assuming that the compiler has to have a mental
	picture for everything ... and that the various instructions
	affect this mental picture in some planned way ... eg. CENTER,
	OPEN, SEARCH, etc. don't change mental position ... but MOVE,
	GO, etc. do ... what about FREE and STOPPING ON FORCE?


MACRO FEEL_POINT(REAL OP1, VECTOR DEP, REAL OP2, VECTOR APP, FRAME POINT,
	VECTOR AXIS, REAL DEG);
    BEGIN COMMENT OP1 ... opening used to leave current position 
		DEP ... depart vector from current position
		OP2 ... opening used to approach the POINT
		APP ... approach vector to the POINT
		POINT ... the transform (frame) for the point
		AXIS ... axis about which the hand rotates DEG degrees for touch;

	OPEN OP1
	MOVE YELLOW TO POINT
		USING DEPARTURE=DEP, APPROACH=APP;
		DURING OPEN OP2;	COMMENT if POINT has an automatic
			restore associated with it, the compiler should 
			add it in to the MOVE;

	CENTER
	IF GRASP < .1 THEN ....
	SET POINT → ⊗;	COMMENT compiler should note that POINT now has a
		new assumed position (ie. a new restore transform) and
		should use it whenever POINT is referenced ... question:
		what should stop or override this automatic restoring???
		(1) another SET on that frame of a frame it is attached
		under (or over if specifically stated) ... (2) moving the
		frame  or any frame it is attached to ... (3) ??? ...
		An explicit restore on POINT should be in addition to 
		the automatic restore?   seems correct ... this would be 
		something like a standard relative position from POINT,
		so the resulting object code would be:  
			MOVE TO POINT
				RESTORE BETTER_ESTIMATE_OF_POINT
				RESTORE RELATIVE_POSITION_FROM_POINT;

		COMMENT notice that the SET will do the right thing if
		the POINT already has an automatically used restore ...
		ie. the planned position for POINT as far as the compiler
		is concerned is the uncorrected position of POINT ... thus
		the set will actually create a transform which is cummulative
		in the sense that it moves POINT (without the auto correction)
		to the current run-time position ... which was arrived at
		by using the auto correction, but the compiler has no way 
		of knowing or guessing what that correction is...;

	OPEN OP2
	MOVE TO POINT modified by DEG about AXIS
		USING DEPARTURE=APPROACH=NIL;	COMMENT since POINT has
			been SET, it has an automatic RESTORE associated with
			it that the compiler should insert;
	CENTER
	IF GRASP < .1 THEN ....
	SET POINT → ⊗;	COMMENT notice that this `auto restore' is a single
		transform which corrects the planned position of the POINT;
    END "FEEL_POINT";





	...	RANDOM COMMENTS

	Instead of thinking of `a program' in HAL ... I would rather think
    of a `conversation' with HAL  (2001 here we come) ... that is, HAL should
    be able to handle commands like: EDIT <PROCEDURE>    DEFINE VECTOR X
	COMPILE <PROCEDURE>     EXECUTE <PROCEDURE>    DISPLAY X
	DO: X ← [1, 0, 1.5]	SAVE <PROCEDURE>	READ <PROGRAM>
	... This view implies HAL is a monitor which can call on its own
    editor, compiler, debugging routines, etc. 
→→→→→→10/15/73  THIS LOOKS RIGHT.  I WILL SOON PUT IN A PAGE ON THE OVERALL
	STRUCTURE OF A HAL RUN.

→→→→→→11/3/73   I HAVE REMOVED MOST OF THIS PAGE, BECAUSE IT WAS OBSOLETE.
	...	SAMPLE PROGRAM : BOLT_ON_FROB   (OCT 22)
→→→→→REVISED AS TO SYNTAX 11/3/73

...global definitions ...

...the world of objects (frames,etc.) initially looks like:

	TABLE
	    BLUE
	    YELLOW
	    BEAM
		BEAM_HOLE
	    FROB
	λ∞rOB_HOLE
		FROB_GRASP
	    BOLT

...this is defined as follows:

FRAME BEAM;
    FRAME (FIXDEF_WRT BEAM) BEAM_HOLE;
	PRELOAD_WITH (BOLLES 2 6 5 0 90 0);
FRAME FROB;
    FRAME (FIXDEF_WRT FROB) FROB_HOLE;
	PRELOAD_WITH (BOLLES 0 4 1 0 90 0);
    FRAME (FIXDEF_WRT FROB) FROB_GRASP;
	PRELOAD_WITH (BOLLES 2 0 1 0 180 0);
FRAME BOLT;


...the object of this program is to bolt the FROB to the BEAM by screwing
   a bolt thru the FROB_HOLE into the BEAM_HOLE ... of course aligning FROB
   correctly

MACRO PICKUP(ARM, OBJECT, GRASP_POS, APPR, OPENING, THICKNESS);
    BEGIN COMMENT this is a macro which picks up an object (with the
		specified ARM's hand) and ATTACH's the object to the hand.
		This is done as follows:
		    (1) open the hand to maximum (to leave current place)
		    (2) move to the grasping position ... using specified
			APPRoach ... and simultaneously closing to the
			OPENING specified for grasping the object
		    (3) centers the hand & checks to make sure that the
			opening doesn't become less than THICKNESS (which
			indicates that the hand missed the object ... in which
			case the arm prints a message to the operator and
			waits for the operator to place the object in the correct
			spot ... when the operator has done this he types a
			"P" and the arm can try again);

	OPEN ARM 4; COMMENT notice specification of "which" hand to open;
	MOVE ARM TO GRASP_POS
	    USING APPROACH = APPR
	    DURING OPEN OPENING;
RETRY:	CENTER ON GRASP < THICKNESS DO
	    BEGIN OUTPUT(STRING(ARM) &" DID NOT GRASP THE OBJECT "&
			STRING(OBJECT) CRLF
			"PLACE OBJECT IN ITS PROPER POSITION AND TYPE A `P'
			TO RETRY" CRLF);
		  OPEN ARM 4
		  WAIT 		COMMENT arm waits for operator's response;
		  GOTO RETRY;
	    END;
	ATTACH OBJECT TO ARM	COMMENT notice that implies that at compile-time
				    the compiler has to know where the hand and
				    object are WRT each other ... this is 
				    generally OK, except if wobbles or stop on
				    force or some freedom has been given to
				    the hand ... thus we should have an 
				    assumption for where something is at the
				    moment;


    END OF PICKUP;


MACRO BOLT_ON_FROB
    BEGIN COMMENT this macro bolts on the FROB to the BEAM and ATTACH's
		the FROB to the BEAM ... for completeness the bolt is also
		ATTACHed to the BEAM ... 
		this is done using two hands (FORK'S AND JOIN'S) as follows:
		    (1) pickup the FROB in the yellow hand ... move it to
			the BEAM and align the two holes
		    (2) at the same time pickup the bolt in the blue hand
		    (3) when both of those have been done ... move the bolt
			to the insertion spot, insert it by searching, and
			screw it in (freeing the yellow hand so FROB can
			move up next to the BEAM as the bolt is tightened)
		    (4) attach the FROB to the BEAM;

	FORK L1;
	PICKUP(YELLOW, FROB, FROB_GRASP, ([0 0 -3] WRT FROB_GRASP), 1, .2);
	    COMMENT notice that after picking up the FROB the world is:
		TABLE
		    YELLOW
			FROB
			    FROB_HOLE
			    FROB_GRASP
		    BLUE
		    BEAM
		    	BEAM_HOLE
		    BOLT;
	MOVE FROB_HOLE TO BEAM_HOLE + [.1 0 0] WRT BEAM_HOLE;
	JOIN L2;
L1:	PICKUP(BLUE, BOLT, BOLT, ([0 0 -3] WRT BOLT), .8, .4);
		COMMENT again probably assume default approach of 3" in
		    the minus Z direction of the grasping position ...;
	JOIN L2;
L2:	MOVE  BOLT TO BEAM_HOLE - [0 0 1.7] WRT BEAM_HOLE;
	SEARCH BLUE
	    INCREMENT .1
	    REPEATING BEGIN MOVE TO ⊗ + [0 0 .5] WRT BLUE
				ON FORCE(Z.BLUE) > 50 DO CONTINUE
			DONE
		      END;
		COMMENT shaky ... assume plane of search is perpendicular
			to current position of the hand ... should say
			something about moving back to "original position
			plus the increment" or something ... CONTINUE means
			stop this trip thru the loop and begin the next ...
			DONE means stop the loop all together;
	MOVE BLUE TO ⊗ + [0 0 1.5] WRT BLUE
	    ON FORCE(Z.BLUE) > 50 DO STOP;
	    USING FREE(Z.FROB_HOLE); 
		COMMENT means compiler has to figure out where FROB_HOLE is
		    etc. notice that it is in yellow hand ....;

	MOVE BLUE TO ⊗
	       THEN BEGIN OUTPUT("DIDN'T REACH TORQUE")
			...
		    END;
	    USING FREE(X.BLUE, Y.BLUE, Z.BLUE, Z.FROB_HOLE),
	    DURING SCREW(60)
	    ON TORQUE(Z.BLUE) > 100 DO STOP
	OPEN BLUE 4;

    END OF BOLT_ON_FROB;
	...	MORE COMMENTS (WHILE I'M THINKING OF THEM)

	We should probably start a "reserved word list"

	Where did the name "HAL.SAM" come from???
		→→→→→→HAL.SAMPLE, of course.  See page 2.
	...
	...